package com.xyy.saas.payment.util.mq;

import com.alibaba.fastjson.JSON;
import com.xyy.saas.payment.api.impl.PaymentOrderApiImpl;
import com.xyy.saas.payment.callback.core.result.CallbackRunner;
import com.xyy.saas.payment.common.RocketMqGroup;
import com.xyy.saas.payment.common.RocketMqTopic;
import com.xyy.saas.payment.cores.bo.SeparateAccountsBo;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.cores.enums.SeparateSummaryStatusEnum;
import com.xyy.saas.payment.cores.vo.BatchSeparateAccountDetailVO;
import com.xyy.saas.payment.cores.vo.CallbackResultVo;
import com.xyy.saas.payment.cores.vo.ResultVO;
import com.xyy.saas.payment.cores.vo.SeparateAccountFromUserVo;
import com.xyy.saas.payment.dao.model.SeparateSummary;
import com.xyy.saas.payment.dao.model.ThirdUserInfo;
import com.xyy.saas.payment.service.PayAccountService;
import com.xyy.saas.payment.service.SeparateSummaryService;
import com.xyy.saas.payment.service.ThirdUserInfoService;
import com.xyy.saas.payment.util.ApolloUtil;
import com.xyy.saas.payment.util.CallbackUtil;
import com.xyy.saas.payment.util.DateUtil;
import com.xyy.saas.payment.util.JSONUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer;
import org.apache.rocketmq.common.UtilAll;
import org.apache.rocketmq.common.consumer.ConsumeFromWhere;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.apache.rocketmq.spring.core.RocketMQPushConsumerLifecycleListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.*;

@Service
@RocketMQMessageListener(topic = RocketMqTopic.TOPIC_SEPARATE_ORDER_CONSUMER, consumerGroup = RocketMqGroup.GROUP_SEPARATE_ORDER_CONSUMER, consumeMode = ConsumeMode.ORDERLY)
public class SeparateOrderConsumer implements RocketMQListener<MessageExt>, RocketMQPushConsumerLifecycleListener {

    private static final Logger LOGGER = LoggerFactory.getLogger(SeparateOrderConsumer.class);
    @Autowired
    private CallbackRunner callbackRunner;
    @Autowired
    private SeparateSummaryService separateSummaryService;
    @Autowired
    CallbackUtil callbackUtil;
    @Resource
    private PaymentOrderApiImpl paymentOrderApi;
    @Resource
    private PayAccountService payAccountService;
    @Resource
    private ThirdUserInfoService thirdUserInfoService;


    @Override
    public void onMessage(MessageExt messageExt) {
        LOGGER.error("SeparateOrderConsumer MQ receive message body:{}.", messageExt.getBody());
        String separateNo = new String(messageExt.getBody());

        if(StringUtils.isBlank(separateNo)) {
            LOGGER.error("SeparateOrderConsumer MQ receive message fail separateNo is blank.");
            return;
        }

        SeparateSummary separateSummary = separateSummaryService.selectBySeparateNo(separateNo);

        if(null == separateSummary) {
            LOGGER.error("SeparateOrderConsumer query separateSummary is not exist. separateSummary:{}", JSONUtils.toJSON(separateSummary));
            return;
        }

        if(separateSummary.getStatus() != SeparateSummaryStatusEnum.CREATE.getStatus()) {
            LOGGER.error("SeparateOrderConsumer separateSummary status is not create status. separateSummary:{}", JSONUtils.toJSON(separateSummary));
            return;
        }

        List<BatchSeparateAccountDetailVO> batchSeparateDetails = JSONUtils.parse2List(separateSummary.getSeparateDetails(), BatchSeparateAccountDetailVO.class);
        // 根据order升序排列
        batchSeparateDetails.sort(Comparator.comparing(BatchSeparateAccountDetailVO::getOrder));

        boolean isFailed = false;
        List<Map<String, Object>> result = new ArrayList<>();

        // 转账 先将主表状体修改为转账中
        SeparateSummary entity = new SeparateSummary();
        entity.setId(separateSummary.getId());
        entity.setStatus(SeparateSummaryStatusEnum.IN_SEPARATE.getStatus());
        entity.setUpdateTime(DateUtil.now());

        if(separateSummaryService.updateById(entity) < 1) {
            LOGGER.error("SeparateOrderConsumer update status error. entity:{}", JSONUtils.toJSON(entity));
            isFailed = true;
        }

        for(BatchSeparateAccountDetailVO batchSeparateDetail : batchSeparateDetails) {
            Map<String, Object> map = new HashMap<>();
            map.put("orderNo", batchSeparateDetail.getOrderNo());
            map.put("amount", batchSeparateDetail.getAmount());

            if(isFailed) {
                // 失败 后面的转账全部终止
                map.put("status", "fail");
                map.put("errorMsg","转账失败终止");
                result.add(map);
                continue;
            }

            // 转账
            SeparateAccountFromUserVo separate = new SeparateAccountFromUserVo();
            separate.setBusinessType(separateSummary.getBusinessType());
            separate.setBusinessIdType(separateSummary.getBusinessIdType());
            separate.setBusinessOrderType(separateSummary.getBusinessOrderType());
            separate.setBusinessOrderNo(batchSeparateDetail.getOrderNo());
            separate.setAmount(batchSeparateDetail.getAmount());
            separate.setBusinessUserIdOut(convert(separateSummary.getBusinessIdType(), separateSummary.getBusinessUserId(), batchSeparateDetail.getFromBusinessUserId()));
            separate.setBusinessUserIdIn(convert(separateSummary.getBusinessIdType(), separateSummary.getBusinessUserId(), batchSeparateDetail.getToBusinessUserId()));
            separate.setBusinessIdTypeOut(separateSummary.getBusinessIdType());
            separate.setBusinessIdTypeIn(separateSummary.getBusinessIdType());
            separate.setExtra(batchSeparateDetail.getSceneDesc());
            ResultVO<SeparateAccountsBo> resultVO = paymentOrderApi.separateAccountFromUser(separate, StringUtils.EMPTY);

            if(ResultCodeEnum.SUCCESS.getCode().equals(resultVO.getCode())) {
                map.put("separateNo", resultVO.getResult().getUserSeparateNo());
                map.put("status", "success");
            }
            else {
                LOGGER.error("SeparateOrderConsumer#onMessage separate error separate:{} error:{}", JSON.toJSONString(separate), JSONUtils.toJSON(resultVO));
                isFailed = true;
                map.put("status","fail");
                map.put("errorMsg", resultVO.getMsg());
            }

            result.add(map);
        }

        SeparateSummary updObj = new SeparateSummary();
        updObj.setId(separateSummary.getId());
        updObj.setStatus(isFailed ? SeparateSummaryStatusEnum.SEPARATE_FAIL.getStatus() : SeparateSummaryStatusEnum.SEPARATE_SUCCESS.getStatus());
        updObj.setErrMsg(isFailed ? JSONUtils.toJSON(result) : "");
        updObj.setUpdateTime(DateUtil.now());

        if(separateSummaryService.updateById(updObj) < 1) {
            LOGGER.error("SeparateOrderConsumer update status error. entity:{}", JSONUtils.toJSON(updObj));
            isFailed = true;
        }

        // 回调业务方
        String type = isFailed ? CallbackResultVo.TRANSFER_ACCOUNTS_FAIL : CallbackResultVo.TRANSFER_ACCOUNTS_SUCCESS;
        Long unixTime = System.currentTimeMillis() / 1000;
        callbackRunner.callback(separateSummary.getSeparateNo(), type, 0, 0, unixTime, separateSummary.getCallback(), "", "", JSONUtils.toJSON(result), separateSummary.getBusinessOrderNo());
        LOGGER.info("SeparateOrderConsumer#onMessage separate end separateSummary:{}", JSON.toJSON(separateSummary));
    }

    @Override
    public void prepareStart(DefaultMQPushConsumer defaultMQPushConsumer) {
        defaultMQPushConsumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        defaultMQPushConsumer.setConsumeTimestamp(UtilAll.timeMillisToHumanString3(System.currentTimeMillis()));
    }

    /**
     * 账户转换，判断是否需要从富民渠道转成易宝渠道
     */
    private String convert(String businessIdType, String businessUserId, String targetBusinessUserId) {
        ThirdUserInfo thirdUserInfo = thirdUserInfoService.getThirdUserInfoByUserId(payAccountService.
                getAccountIdByBusiness(businessIdType, businessUserId));

        // 例子 settlement_account_mapping_yop_heye_platform
        String key = "settlement_account_mapping_" + thirdUserInfo.getThirdType() + "_" + targetBusinessUserId;
        String value = ApolloUtil.getProperty(key);
        return StringUtils.isNotBlank(value) ? value : targetBusinessUserId;
    }
}
